package run.halo.app.controller.front.api;

import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSONObject;
import java.io.IOException;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.request.AuthWeChatOpenRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import run.halo.app.model.dto.front.BindMobileDTO;
import run.halo.app.model.dto.front.LoginDTO;
import run.halo.app.model.dto.front.MobileMsgDTO;
import run.halo.app.model.entity.front.Customer;
import run.halo.app.model.support.FrontConstant;
import run.halo.app.security.token.AuthToken;
import run.halo.app.service.front.CustomerService;
import run.halo.app.service.front.FrontService;
import run.halo.app.service.front.MsgService;
import run.halo.app.common.R;

@Slf4j
@Controller
@RequestMapping("/api/front")
public class FrontController {
    @Value("${auth2.tencent.clientId}")
    private String clientId;
    @Value("${auth2.tencent.clientSecret}")
    private String clientSecret;
    @Value("${auth2.tencent.redirectUri}")
    private String redirectUri;
    @Value("${msg.maxCount}")
    private int maxCount;

    private final CustomerService customerService;
    private final FrontService frontService;
    private final MsgService msgService;
    private final StringRedisTemplate redisTemplate;

    public FrontController(CustomerService customerService,
        FrontService frontService, MsgService msgService,
        StringRedisTemplate redisTemplate) {
        this.customerService = customerService;
        this.frontService = frontService;
        this.msgService = msgService;
        this.redisTemplate = redisTemplate;
    }


    /**
     * 第三方登录重定向
     *
     * @param source
     * @param response
     * @throws IOException
     */
    @RequestMapping("/render/{source}")
    @ResponseBody
    public void renderAuth(@PathVariable("source") String source, HttpServletResponse response)
        throws
        IOException {
        log.info("进入render：" + source);
        AuthRequest authRequest = getAuthRequest(source);
        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
        log.info(authorizeUrl);
        response.sendRedirect(authorizeUrl);
    }

    /**
     * 第三方登录重定向
     *
     * @param source
     * @param response
     * @throws IOException
     */
    @RequestMapping("/oauth2/{source}")
    @ResponseBody
    public String getAuthCodeUrl(@PathVariable("source") String source, HttpServletResponse response)
        throws
        IOException {
        log.info("进入render：" + source);
        AuthRequest authRequest = getAuthRequest(source);
        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
        log.info(authorizeUrl);
        return authorizeUrl;
    }

    /**
     * 第三方登录回调
     *
     * @param source
     * @param callback
     * @param request
     * @return
     */
    @GetMapping("/callback/{source}")
    public String login(@PathVariable("source") String source, AuthCallback callback,
        HttpServletRequest request,
        Model model) {
        log.info("进入callback：" + source + " callback params：" + JSONObject.toJSONString(callback));
        AuthRequest authRequest = getAuthRequest(source);
        AuthResponse<AuthUser> response = authRequest.login(callback);
        log.info(JSONObject.toJSONString(response));
        if (response.ok()) {
            //通过UUID去查询用户表是否有用户的注册信息
            Optional<Customer> opcustomer =
                customerService.findByUuid(response.getData().getUuid());
            if (opcustomer.isEmpty()) {
                frontService.saveCustomer(response.getData());
                model.addAttribute("user", response.getData());
                return "front/bind_mobile";
            }
            Customer customer = opcustomer.get();
            //如果电话号码是空，则跳转到绑定手机界面
            if (ObjectUtil.isEmpty(customer.getPhoneNumber())) {
                model.addAttribute("user", customer);
                return "front/bind_mobile";
            }
            //保存用户登录信息
            //跳转到成功界面
            AuthToken authToken = frontService.cacheAuthCustomer(customer);
            model.addAttribute("user", customer);
            model.addAttribute("authToken", authToken);
            return "front/success";
        }
        model.addAttribute("message", response.getMsg());
        return "common/error/error";
    }


    @GetMapping("/sendMsg/{phoneNo}")
    @ResponseBody
    public R<Boolean> sendMobileMsg(@PathVariable String phoneNo,HttpServletRequest request) {
        if (ObjectUtil.isEmpty(phoneNo)) {
            return R.fail("手机号不能为空！");
        }
        boolean isMobile = Validator.isMobile(phoneNo);
        if (!isMobile) {
            return R.fail("手机号格式不正确！");
        }
        String clientIP = ServletUtil.getClientIP(request, "");
        String count = redisTemplate.opsForValue()
            .get(FrontConstant.REDIS_CLIENT_IP_KEY + clientIP);
        if(StrUtil.isNotEmpty(count)){
            if(Integer.parseInt(count) > maxCount){
                return R.ok(true,"高台贵手，短信太贵，您短信玩得可还好！");
            }
        }

        //发送短信
        return R.ok(true, msgService.sendMobileMsg(phoneNo,clientIP));
    }

    @PostMapping("/mobileLogin")
    @ResponseBody
    public R<AuthToken> oauthMobileMsg(@RequestBody MobileMsgDTO msgDTO) {
        if (ObjectUtil.isEmpty(msgDTO) || ObjectUtil.isEmpty(msgDTO.getPhoneNo())) {
            return R.fail("手机号不能为空！");
        }
        boolean isMobile = Validator.isMobile(msgDTO.getPhoneNo());
        if (!isMobile) {
            return R.fail("手机号格式不正确！");
        }
        if (ObjectUtil.isEmpty(msgDTO) || ObjectUtil.isEmpty(msgDTO.getCode())) {
            return R.fail("验证码不能为空！");
        }
        return frontService.checkMobileCode(msgDTO);
    }

    @PostMapping("/bindMobile")
    @ResponseBody
    public R<AuthToken> bindMobile(@RequestBody BindMobileDTO bindMobileDTO){
        if (ObjectUtil.isEmpty(bindMobileDTO) || ObjectUtil.isEmpty(bindMobileDTO.getPhoneNo())) {
            return R.fail("手机号不能为空！");
        }
        if (ObjectUtil.isEmpty(bindMobileDTO) || ObjectUtil.isEmpty(bindMobileDTO.getCode())) {
            return R.fail("验证码不能为空！");
        }
        if (ObjectUtil.isEmpty(bindMobileDTO) || ObjectUtil.isEmpty(bindMobileDTO.getUuid())) {
            return R.fail("uuid不能为空！");
        }
        return frontService.bindMobile(bindMobileDTO);
    }


    /**
     * 获取第三方登录获取认证请求
     *
     * @param source
     * @return
     */
    private AuthRequest getAuthRequest(String source) {
        AuthRequest authRequest = null;
        switch (source.toLowerCase()) {
            case "wechat_open":
                authRequest = new AuthWeChatOpenRequest(AuthConfig.builder()
                    .clientId(clientId)
                    .clientSecret(clientSecret)
                    .redirectUri(redirectUri)
                    .build());
                break;
            default:
                break;
        }
        if (null == authRequest) {
            throw new AuthException("未获取到有效的Auth配置");
        }
        return authRequest;
    }


    @PostMapping("/login")
    @ResponseBody
    public R<AuthToken> login(@RequestBody LoginDTO dto){
        if (ObjectUtil.isEmpty(dto) || ObjectUtil.isEmpty(dto.getCode())) {
            return R.fail("code is not null！");
        }

        return frontService.miniAppLogin(dto);
    }

    @GetMapping("/createWxaCode")
    @ResponseBody
    public R<String> createWxaCode(@RequestParam("path") String path){
       return frontService.createWxaCode(path);
    }

    @GetMapping("/checkLogin")
    @ResponseBody
    public R<?> checkLogin(@RequestParam("uuid") String uuid){
        return frontService.checkLogin(uuid);
    }


}
